<!--
 * @Author: 黄达全
 * @Date: 2024-07-29 14:39:44
 * @LastEditTime: 2024-08-16 19:07:06
-->
<script lang="ts" setup>
import type { AccessItem, AccessAddForm } from "@/common/type"
import RuleApi from "@/api/model/rule"
import { ref, reactive, watch } from "vue"
import drawer from "@/components/drawer.vue"
import useComRef from "@/hooks/useComRef"
import { ElForm } from "element-plus"
import selectIcon from "@/components/selectIcon.vue"
import useElementPlus from "@/hooks/useElementPlus"

const height = document.documentElement.clientHeight - 44.33 - 42 - 60.67 - 14;

// 获取权限信息
const accessData = ref<AccessItem[]>([])
// 默认展开节点id
const defaultExpandKeys = ref<number[]>([])
const setDefaultExpandKeys = (access: AccessItem) => {
    defaultExpandKeys.value.push(access.id)
    if (!access.child) return
    access.child.forEach(item => setDefaultExpandKeys(item))
}
const setTreeItemStatus = (access: AccessItem) => {
    access.status = access.status == 1 ? true : false
    if (!access.child) return access
    access.child.forEach(item => {
        setTreeItemStatus(item)
    })
    return access
}
const getAccessData = async () => {
    const res = await RuleApi.select()
    accessData.value = res.data.map(item => {
        return setTreeItemStatus(item)
    })
    setDefaultExpandKeys(res.data[0])
}
getAccessData()
const defaultProps = {
    children: 'child',
    label: 'name',
    class: "tree-node-class"
}

const isDrawerAdd = ref(true)
const drawerRef = ref<InstanceType<typeof drawer>>()
const drawerFormRef = useComRef(ElForm)

const is_disabled=ref<boolean>(false)
const accessForm = reactive<AccessAddForm>({
    ruleId: 0,
    menu: 1,
    name: "",
    condition: "",
    method: "GET",
    order: 0,
    frontpath: "",
    icon: ""
})
const drawerFormRules = reactive({
    ruleId: [
        { required: true, message: '请选择权限', trigger: 'change' },
    ],
    menu: [
        { required: true, message: '请选择菜单', trigger: 'change' },
    ],
    name: [
        { required: true, message: '请输入名称', trigger: 'blur' },
    ],
    condition: [
        { required: true, message: '请输入后端规则', trigger: 'blur' },
    ],
    frontpath: [
        { required: true, message: '请输入前端路径', trigger: 'blur' },
        { pattern: /^\/[a-zA-Z0-9\-_]+(\/[a-zA-Z0-9\-_]+)*$/, message: '前端路径格式错误', trigger: 'blur' },
    ],
    method: [
        { required: true, message: '请选择请求方式', trigger: 'change' },
    ],
    order: [
        { required: true, message: '请输入排序', trigger: 'blur' },
    ]
})

// 控制菜单/权限的表单显示
const isMenuForm = ref(true)

watch(() => accessForm.menu, (newVal) => {
    isMenuForm.value = newVal == 1 ? true : false
})



// 打开新增弹窗
const openAddDrawer = (id?:number) => {
    const flag=typeof id === "number"
    if(flag){
        is_disabled.value=true
    }
    isDrawerAdd.value = true
    drawerRef.value?.open()
    accessForm.ruleId = flag?id:0
    accessForm.menu = 1
    accessForm.name = ""
    accessForm.condition = ""
    accessForm.method = "GET"
    accessForm.order = 0
    accessForm.frontpath = ""
}
const radioIsDisable=ref<boolean>(false)
const editId=ref<number>()
const editStatus=ref<number>()
// 打开编辑弹窗
const openEditDrawer = (id:number,access:AccessItem) => {
    editId.value=id
    editStatus.value=access.status?1:0 
    if(access.ruleId===0) is_disabled.value=true
    radioIsDisable.value=true
    isDrawerAdd.value = false
    drawerRef.value?.open()
    accessForm.ruleId=access.ruleId;
    accessForm.menu=access.menu;
    accessForm.name=access.name;
    accessForm.condition=access.condition!;
    accessForm.method=access.method as 'GET' | 'POST' | 'PUT' | 'DELETE'
    accessForm.order=access.order!;
    accessForm.frontpath=access.frontpath!;
    accessForm.icon=access.icon;
}

const { message, messageBox } = useElementPlus()
// 新增权限
const addAccess = async () => {
    const valid = await drawerFormRef.value?.validate().catch((err: any) => console.log(err))
    if (!valid) return
    const { code } = await RuleApi.add(accessForm)

    if (code == 1) {
        message({
            message: "新增成功",
            type: "success"
        })
        getAccessData()
        drawerRef.value?.close()
    }else{
        message({
            message: "新增失败",
            type: "error"
        })
    }
}
// 编辑权限
const editAccess =async () => {
    const valid = await drawerFormRef.value?.validate().catch((err: any) => console.log(err))
    if (!valid) return
    const { code } = await RuleApi.edit(editId.value!,{
        ...accessForm,
        status:editStatus.value!
    })

    if (code == 1) {
        message({
            message: "编辑成功",
            type: "success"
        })
        getAccessData()
        drawerRef.value?.close()
    }else{
        message({
            message: "编辑失败",
            type: "error"
        })
    }
    
}

// 删除权限/菜单
const deleteAccess = (id: number) => {
    messageBox("提示", "是否删除此权限", "warning").then(async () => {
        const { code } = await RuleApi.delete(id)
        if (code == 1) {
            message({
                message: "删除成功",
                type: "success"
            })
            getAccessData()
        } else {
            message({
                message: "删除失败",
                type: "error"
            })
        }

    }).catch(() => {
        message({
            message: "取消删除",
            type: "info"
        })
    })
}

// 弹窗提交
const drawerSubmitHandle = () => {
    isDrawerAdd.value ? addAccess() : editAccess()
}

const menuData = ref<AccessItem[]>([])
watch(accessData, (newVal) => {
    const filteredData = (item: AccessItem): AccessItem | null => {
        if (item.menu == 0 || item.child == null) return null
        const newChild = item.child.map(i => filteredData(i)).filter(i => i !== null) as AccessItem[]
        return { ...item, child: newChild }
    }
    menuData.value = newVal.map(i => filteredData(i)).filter(i => i !== null) as AccessItem[]
})


const cascaderHandleChange = (e: any) => {
    accessForm.ruleId = e[e.length - 1]
}
const cascaderProps = {
    children: "child",
    label: 'name',
    value: 'id',
    expandTrigger: 'hover' as const,
    checkStrictly: true,
}

const radioChangeHandle = () => {
    drawerFormRef.value?.clearValidate(["frontpath", "condition", "name"])
    accessForm.condition = ""
    accessForm.frontpath = ""
    accessForm.name = ""
    accessForm.icon = ""

}


const closeDrawerHandle=()=>{
    is_disabled.value=false
    radioIsDisable.value=false
}

const switchHandle=async(e:boolean | string | number,id:number)=>{
    const { code } = await RuleApi.edit(id,{
        status:e?1:0
    })

    if (code == 1) {
        message({
            message: "修改状态成功",
            type: "success"
        })
        getAccessData()
        drawerRef.value?.close()
    }else{
        message({
            message: "修改状态失败",
            type: "error"
        })
    }
    
}
</script>

<template>
    <div class="AccessPage">
        <el-card class="card" :body-style="{ height: height + 'px', padding: '10px 10px 0 10px', overflowY: 'scroll' }">
            <template #header>
                <div class="card-header">
                    <div class="card-header-left">
                        <el-button color="var(--primary-theme-color)" icon="el-icon-plus" size="small" type="primary"
                            @click="openAddDrawer">新增权限</el-button>
                    </div>
                </div>
            </template>
            <div class="card-body">
                <el-tree :data="accessData" :props="defaultProps" node-key="id" empty-text="内容为空"
                    :highlight-current="true" :default-expanded-keys="defaultExpandKeys">

                    <template #default="{ data }">
                        <div class="tree-item">
                            <div class="tree-item-left">
                                <el-tag :type="data.menu == 0 ? 'info' : 'success'" style="margin-right: 8px;">{{
            data.menu == 0 ? '权限' : '菜单' }}</el-tag>
                                <el-icon>
                                    <component v-if="data.icon" :is="`el-icon-${data.icon}`" />
                                    <component v-else is="el-icon-document" />
                                </el-icon>
                                <span style="margin-left: 8px">{{ data.name }}</span>
                            </div>
                            <div class="tree-item-right">
                                <el-switch v-model="data.status" @change="switchHandle($event,data.id)"  style="--el-switch-on-color: var(--primary-theme-color); --el-switch-off-color: #ccc ;margin-right: 8px;" @click.stop />
                                <el-button v-if="data.menu == 1" link type="primary"
                                    @click.stop="openAddDrawer(data.id)">新增</el-button>
                                <el-button link type="warning" @click.stop="openEditDrawer(data.id,data)">修改</el-button>
                                <el-button link type="danger" @click="deleteAccess(data.id)">删除</el-button>
                            </div>
                        </div>

                    </template>
                </el-tree>
            </div>
        </el-card>
        <drawer ref="drawerRef" :title="isDrawerAdd ? '新增权限' : '修改权限'" direction="rtl" size="35%"
            @submit="drawerSubmitHandle" @closeEvent="closeDrawerHandle">
            <template #rtl>
                <el-form ref="drawerFormRef" :model="accessForm" :rules="drawerFormRules" label-width="95px">
                    <el-form-item label="上级菜单" prop="ruleId">
                        <el-cascader v-model="accessForm.ruleId" :options="menuData" :props="cascaderProps"
                            @change="cascaderHandleChange" placeholder="请选择上级菜单" :disabled="is_disabled"/>
                    </el-form-item>
                    <el-form-item label="菜单/规则" prop="menu">
                        <el-radio-group v-model="accessForm.menu" @change="radioChangeHandle" :disabled="radioIsDisable">
                            <el-radio :value="1" border>菜单</el-radio>
                            <el-radio :value="0" border>规则</el-radio>
                        </el-radio-group>
                    </el-form-item>

                    <template v-if="!isMenuForm">
                        <el-form-item label="权限名称" prop="name">
                            <el-input v-model="accessForm.name" placeholder="请输入权限名称" />
                        </el-form-item>
                      
                        <el-form-item label="后端规则" prop="condition">
                            <el-input v-model="accessForm.condition" placeholder="请输入后端规则" />
                        </el-form-item>
                        <el-form-item label="请求方式" prop="method">
                            <el-select v-model="accessForm.method" placeholder="请输入请求方式">
                                <el-option v-for="item in ['GET', 'POST', 'PUT', 'DELETE']" :key="item" :label="item"
                                    :value="item" />
                            </el-select>
                        </el-form-item>
                    </template>
                    <template v-else>
                        <el-form-item label="菜单名称" prop="name">
                            <el-input v-model="accessForm.name" placeholder="请输入菜单名称" />
                        </el-form-item>
                        <el-form-item label="前端路由" >
                            <el-input v-model="accessForm.frontpath" placeholder="请输入前端路由" />
                        </el-form-item>
                        <el-form-item label="菜单图标" prop="icon">
                            <select-icon v-model="accessForm.icon" />
                        </el-form-item>
                    </template>

                    <el-form-item label="排序" prop="order">
                        <el-input-number :min="0" v-model="accessForm.order" />
                    </el-form-item>
                </el-form>
            </template>
        </drawer>
    </div>
</template>

<style lang="scss" scoped>
.AccessPage {
    height: 100%;

    .card-body {
        .tree-item {
            width: 100%;
            display: flex;
            justify-content: space-between;
            align-items: center;
            height: 40px;

            .tree-item-left {
                display: flex;
                align-items: center;
            }

        }
    }
}

:deep(.tree-node-class > .el-tree-node__content) {
    height: 40px !important;
}
</style>
